เคล็ดลับสำหรับแหล่งที่มาที่ จำกัด ใน Python
เช่นเดียวกับรหัสกอล์ฟ , จำกัด แหล่งที่มาผลักดันหนึ่งที่จะใช้ประโยชน์จากมาตรฐานและคุณลักษณะที่ซ่อนอยู่ของภาษา Python เรามีสถานที่สำหรับรวบรวมเคล็ดลับเหล่านี้ทั้งหมดสำหรับการเล่นโค้ดกอล์ฟแล้วคำแนะนำสำหรับแหล่งที่มาที่ จำกัดยังคงถูกถ่ายทอดโดยปากต่อปากหรือซ่อนอยู่ลึก ๆ ในเอกสาร Python
ดังนั้นวันนี้ผมอยากจะขอให้คุณสิ่งที่บางส่วนเคล็ดลับสำหรับการแก้จำกัด แหล่งที่มาของความท้าทายในการงูใหญ่?
โปรดระบุเพียง 1 เคล็ดลับต่อคำตอบ
เคล็ดลับดีๆที่นี่คืออะไร?
มีเกณฑ์สองสามข้อที่ฉันคิดว่าเคล็ดลับที่ดีควรมี:
มันควรจะ (ค่อนข้าง) ไม่ชัดเจน
คล้าย ๆ กับcode-golf tips น่าจะเป็นสิ่งที่คนที่เคยตีกอล์ฟใน python มาหน่อยแล้วอ่านหน้า tips จะไม่นึกถึงทันที ตัวอย่างเช่น "แทนที่
a + b
ด้วยa+b
เพื่อหลีกเลี่ยงการใช้ช่องว่าง" นักกอล์ฟทุกคนเห็นได้ชัดเนื่องจากเป็นวิธีที่ทำให้โค้ดของคุณสั้นลงอยู่แล้วจึงไม่ใช่เคล็ดลับที่ดีไม่ควรเจาะจงเกินไป
เนื่องจากข้อ จำกัด แหล่งที่มามีหลายประเภทคำตอบที่นี่จึงควรใช้ได้กับข้อ จำกัด หลายแหล่งหรือข้อ จำกัด แหล่งที่มาทั่วไปอย่างน้อยหนึ่งข้อ ตัวอย่างคำแนะนำของแบบฟอร์มHow to X โดยไม่ใช้อักขระ Yมักมีประโยชน์เนื่องจากอักขระที่ถูกแบนเป็นข้อ จำกัด ของแหล่งที่มาทั่วไป สิ่งที่เคล็ดลับของคุณช่วยในการทำควรเป็นเรื่องทั่วไปด้วย ตัวอย่างเคล็ดลับของแบบฟอร์มวิธีสร้างตัวเลขด้วยข้อ จำกัด Xมีประโยชน์เนื่องจากหลายโปรแกรมใช้ตัวเลขโดยไม่คำนึงถึงความท้าทาย เคล็ดลับของแบบฟอร์มวิธีใช้อัลกอริทึมของ Shor ด้วยข้อ จำกัด Xโดยพื้นฐานแล้วเป็นเพียงคำตอบสำหรับความท้าทายที่คุณเพิ่งคิดค้นและไม่เป็นประโยชน์กับผู้คนในการแก้ปัญหาอื่น
คำตอบ
หลีกเลี่ยงตัวอักษร "ปกติ"
ตัวระบุถูกทำให้เป็นมาตรฐานโดยตัวแยกวิเคราะห์ Python 3 นี่ก็หมายความว่าเล่นหาง (Unicode) ตัวอักษรเช่นจะถูกตีความเป็นเทียบเท่า𝓪𝓫𝓬𝓓𝓔𝓕
ASCII ที่สอดคล้องกับของพวกเขา abcDEF
ดังนั้นรหัสต่อไปนี้ใช้งานได้ (ตามที่ใช้ประโยชน์ที่นี่ ):
𝓝=123
𝓹𝓻𝓲𝓷𝓽(𝓝)
เวอร์ชัน Python ที่ยืนยันพฤติกรรมนี้:
- งาน: 3.4, 3.5, 3.6, 3.7, 3.8
- ไม่ทำงาน: 2.7
ตัวอย่างข้อ จำกัด แหล่งที่มา:
- ใช้ตัวอักษรไม่,
abc···xyz
ABC···XYZ
หลีกเลี่ยงตัวเลขที่มีบูลีน
เมื่อทำการคำนวณทางคณิตศาสตร์บนบูลีน Python จะถือว่าพวกมันเป็นตัวเลข 1 และ 0 ตัวอย่างเช่น
>>> True+False
1
คุณสามารถสร้างจำนวนบวกทั้งหมดได้เพียงแค่เพิ่มบูลีนเข้าด้วยกัน
คุณยังสามารถแทนที่บูลีนสำหรับค่าบูลีนได้เช่น[]>[]
is False
and [[]]>[]
is True
so
>>> ([]>[])+([[]]>[])
1
ในบางกรณี Booleans สามารถใช้แทนตัวเลขได้โดยไม่ต้องใช้เลขคณิตในการร่าย ตัวอย่างเช่นคุณสามารถจัดทำดัชนีเป็นรายการ / tuples / สตริงด้วยบูลีนได้ดังนั้น:
>>> ['a','b'][True]
'b'
ตัวอย่างข้อ จำกัด แหล่งที่มา:
ไม่ใช้ตัวเลข (
0123456789
)ไม่ใช้อักขระที่เป็นตัวเลขและตัวอักษร
ไม่ใช้
if
เงื่อนไข
หลีกเลี่ยง Parens ด้วยการจัดทำดัชนีรายการ
วงเล็บมีประโยชน์อย่างยิ่งสำหรับการสร้างลำดับความสำคัญของตัวดำเนินการที่ถูกต้องดังนั้นจึงเป็นเรื่องที่น่าเบื่อเมื่อถูกแบน อย่างไรก็ตามหาก[]
ยังมีอยู่เราสามารถใช้แทนได้ เพียงแค่เปลี่ยน
(...)
ด้วย
[...][0]
สิ่งนี้จะสร้างรายการและทำดัชนีเพื่อให้ได้องค์ประกอบเดียว รายการทำให้ภายในได้รับการประเมินก่อนเพื่อแก้ปัญหาลำดับความสำคัญของคุณ
ตัวอย่างด้านบนใช้อักขระ[]0
เพื่อทำสิ่งนี้ แต่มีอักขระที่สามอื่น ๆ ที่สามารถใช้ในกรณีนี้ได้หากจำเป็น
- การใช้อักขระ
[]>
เขียน[...][[]>[]]
- การใช้อักขระ
[]<
เขียน[...][[]<[]]
- การใช้อักขระ
[]=
เขียน[...][[[]]==[]]
ตัวอย่างข้อ จำกัด แหล่งที่มา:
- ไม่ต้องใช้วงเล็บ
การเรียกใช้ฟังก์ชันโดยไม่มีวงเล็บ
เราสามารถหลีกเลี่ยงการใช้วงเล็บสำหรับลำดับความสำคัญของตัวดำเนินการได้โดยใช้การจัดทำดัชนีรายการแต่วงเล็บยังคงมีประโยชน์มากสำหรับการเรียกใช้ฟังก์ชัน
การจัดทำดัชนีรายการสามารถใช้ที่นี่เพื่อแก้ปัญหาได้ แต่มันซับซ้อนกว่ามากดังนั้นฉันจึงได้คำตอบของมันเอง
ในการเรียกใช้ฟังก์ชันเราเริ่มต้นด้วยการสร้างคลาสใหม่ซึ่งมีการกำหนดดัชนีให้เป็นฟังก์ชัน ดังนั้นถ้าเราต้องการเรียกprint
สิ่งนี้อาจมีลักษณะดังนี้
class c:__class_getitem__=print
จากนั้นในการเรียกใช้ฟังก์ชันเราก็ทำดัชนีด้วยอาร์กิวเมนต์ที่เราต้องการ ตัวอย่างเช่นในการพิมพ์ที่"Hello World"
เราทำ
c["Hello World"]
สิ่งนี้มีการมาถึงสั้น ๆ ที่โชคร้าย:
- สามารถใช้เพื่อเรียกใช้ฟังก์ชันที่มีพารามิเตอร์เดียวเท่านั้น
- มีอักขระไม่กี่ตัวที่ต้องใช้เพื่อดึงเคล็ดลับนี้ออก (
:=[]_acegilmst
) - มันใช้อักขระจำนวนมากหากคุณกำลังทำโค้ดกอล์ฟ
แต่บางครั้งอาจเป็นทางเลือกเดียวของคุณ
ตัวอย่างข้อ จำกัด แหล่งที่มา:
- ไม่ต้องใช้วงเล็บ
นี่คือตัวอย่างของการใช้งาน
ใช้<<
และ|
สร้างค่าคงที่โดยไม่ต้อง+
สนุกจริง: คุณจะได้รับอย่างต่อเนื่องบวกใด ๆ []<|
เพียงแค่ใช้ วิธีที่จะไปคือการเปลี่ยนบูลีนทางซ้าย []<[[]]
คือ 1 ดังนั้น[]<[[]]<<[]<[[]]
ควรเลื่อนไปทางซ้าย 1 กับ 1 ซึ่งก็คือ 2
ได้ผลหรือไม่?
>>> []<[[]]<<[]<[[]]
Traceback (most recent call last):
File "<pyshell#29>", line 1, in <module>
[]<[[]]<<[]<[[]]
TypeError: unsupported operand type(s) for <<: 'list' and 'list'
... เปล่าครับ
ลำดับความสำคัญผิด โชคดีที่เราสามารถแก้ไขปัญหานี้ได้ด้วย "Ad Hoc Garf Hunter Parenthesis (TM)":
>>> [[]<[[]]][[]<[]]<<[[]<[[]]][[]<[]]
2
อ๊าาา!
เพื่อให้ได้ตัวเลขอื่นที่ไม่ใช่กำลังสองคุณยังต้องการ+
... หรือไม่ |
หรือ[bitwise or][[]<[]]
* จะทำเพื่อคุณ
>>> [[]<[[]]][[]<[]]<<[[]<[[]]][[]<[]]<<[[]<[[]]][[]<[]]<<[[]<[[]]][[]<[]]|[[]<[[]]][[]<[]]<<[[]<[[]]][[]<[]]
10
เพื่อให้ได้ตัวเลขที่ติดลบโดยไม่ต้องคุณอาจต้องการที่จะใช้-
~
* ส่วนนั้นอยู่ใน "Ad Hoc Garf Hunter Parenthesis (TM)" เพื่อระบุลำดับความสำคัญ
เข้าถึงวิธีการและฟังก์ชันในตัวผ่าน __dict__
คลาสประกอบด้วย__dict__
แอตทริบิวต์ซึ่งแมปชื่อเมธอดกับเมธอด __dict__
ถ้าคุณไม่สามารถพิมพ์ชื่อวิธีการโดยตรงคุณสามารถรับพวกเขาจากนี้
ตัวอย่างเช่นสมมติว่าคุณต้องต่อท้ายรายการ แต่คุณไม่สามารถใช้อักขระp,n,+
ได้เป็นต้นเนื่องจากappend()
เป็นวิธีที่ 26 ในรายการ__dict__
คุณสามารถเรียกใช้เมธอดดังนี้:
a = [1,2,3]
list(a.__class__.__dict__.values())[26](a, 4)
print(a) # prints [1,2,3,4]
ลองออนไลน์!
นอกจากนี้ยังสามารถใช้__builtins__
เพื่อเข้าถึงฟังก์ชันในตัว แม้ว่าจะมีคนห้ามอักขระx
เพื่อบล็อกexec
ฟังก์ชันนี้คุณก็ยังสามารถเรียกexec
สิ่งนี้ได้:
list(__builtins__.__dict__.values())[20]("print('Hello, World!')")
ลองออนไลน์!
วิธีนี้ใช้ได้ดีที่สุดใน Python เวอร์ชันล่าสุดที่รับประกันคำสั่งพจนานุกรม แต่อาจมีวิธีอื่นในการใช้สิ่งนี้ในเวอร์ชันเก่าเช่นการวนซ้ำ__dict__
ด้วย regex หรือการจับคู่สตริงย่อย
ใช้ord()
หรือสตริงไบนารีเพื่อหลีกเลี่ยงตัวเลข
จำนวนเต็มส่วนใหญ่ในช่วง[32..47]
และ[58..126]
สามารถหาได้อย่างง่ายดายจากรหัส ASCII ของอักขระเดี่ยวด้วย:
x=ord('A')
# or, if parentheses are not allowed:
y=b'A'[False]
ลองออนไลน์!
นอกจากนี้ยังสามารถสร้างจำนวนเต็มขนาดใหญ่ได้โดยใช้จากจุดยูนิโคด:
>>>print (ord("±"))
177
>>> print (ord("π"))
960
หากคุณสามารถใช้การกำหนดหรือคุณต้องการหลีกเลี่ยงวงเล็บคุณสามารถแกะค่าแทนได้ โปรดทราบว่าสิ่งนี้จะไม่ทำงานแบบอินไลน์แม้ว่าจะใช้ตัวดำเนินการวอลรัสก็ตาม
x,*_=b'A'
y,_=b'A_'
ลองออนไลน์!
ตัวอย่างข้อ จำกัด แหล่งที่มา:
- ไม่ใช้ตัวเลข
- ไม่ใช้ตัวเลข / ไม่มีวงเล็บ / ไม่มีวงเล็บ
ใช้--
เพื่อหลีกเลี่ยง +
เช่นสิ่งที่ต้องทำa+b
:
a--b
ตัวอย่างข้อ จำกัด แหล่งที่มา:
- หลีกเลี่ยงตัว
+
ดำเนินการ
ทางเลือกในการeval
และexec
คุณจำเป็นต้องถือว่าสตริงเป็นรหัส แต่คุณไม่สามารถใช้eval
หรือexec
? มีอย่างน้อยสามวิธีอื่น ๆ ในการดำเนินการสตริง:
1) timeit.timeit
import timeit
_=timeit.timeit("print('Hello!')", number=1)
ลองออนไลน์!
timeit
number
เวลาทำงานและส่งกลับค่าเฉลี่ยของระยะเวลาที่ใช้ โดยค่าเริ่มต้นจะทำงาน 1 ล้านครั้งดังนั้นคุณแทบจะต้องการตั้งค่าnumber=1
หรือเพิ่มข้อยกเว้นเพื่อแยกออก (เช่น"print('hello'); 0/0"
)
ขอบคุณEthan White ที่แสดงให้ฉันเห็นแนวทางนี้
2) os.system
import os
c='echo "import math;print(math.pi)" | python3'
_=os.system(c) # Prints 3.141592653589793
ลองออนไลน์!
os.system
รันคำสั่งเชลล์โดยพลการและส่งคืนรหัสทางออก หากคุณต้องการพิมพ์บางอย่างคุณสามารถติดได้echo
แต่คุณยังสามารถเรียกใช้รหัสโดยอำเภอใจได้ด้วยการเรียกpython3
ตัวเอง
3) code.InteractiveInterpreter (). runcode
from code import InteractiveInterpreter as I
i = I()
i.runcode("print('Hello!')")
ลองออนไลน์!
code
ได้รับการออกแบบมาโดยเฉพาะสำหรับลูปแบบ read-eval-print และแม้ว่ามันจะค่อนข้างเกะกะ แต่นี่ก็เป็นสิ่งที่ทรงพลังที่สุดในสาม timeit
และos.system
แยกกระบวนการของพวกเขาออก แต่InteractiveInterpreter
สามารถใช้ global state แทนของมันเอง:
from code import InteractiveInterpreter as I
a = 64
i = I(globals())
i.runcode("import math; a=math.log2(a)")
print(a) # a = 6.0
print(math.pi) # math is imported globally
ลองออนไลน์!
ใช้*
เพื่อหลีกเลี่ยง/
x**-1
เทียบเท่ากับ1/x
. ดังนั้นจะทำอย่างไรที่คุณสามารถทำได้y/x
x**-1*y
หากคุณต้องการกำจัดสิ่งนี้อย่างสิ้นหวัง-1
คุณสามารถดูเคล็ดลับอื่น ๆ ของ Ad Hoc Garf Hunter
ตัวอย่างข้อ จำกัด แหล่งที่มา:
- หลีกเลี่ยงการใช้
/
ตัวละคร
เข้ารหัสอักขระที่ จำกัด และใช้ exec()
เช่นเดียวกับการแปลภาษามากที่สุด, Python สามารถเรียกใช้สตริงเป็นรหัสที่มีและeval
มีข้อ จำกัด มากขึ้น แต่สามารถจัดการกับการนำเข้านิยามฟังก์ชันลูปข้อยกเว้น ฯลฯexec
eval
exec
เมื่อรวมกับเคล็ดลับอื่น ๆ เกี่ยวกับการเข้ารหัสอักขระจะช่วยให้คุณสามารถเขียนโค้ดได้ตามปกติ:
import sys
def f(i):
return 1 if i==1 else i*f(i-1)
i=int(sys.argv[1])
print(f(i))
จากนั้นเลือกการเข้ารหัสและส่งผ่านเวอร์ชันที่เข้ารหัสไปที่exec
:
exec('\x69\x6d\x70\x6f\x72\x74\x20\x73\x79\x73\x0a\x0a\x64\x65\x66\x20\x66\x28\x69\x29\x3a\x0a\x20\x72\x65\x74\x75\x72\x6e\x20\x31\x20\x69\x66\x20\x69\x3d\x3d\x31\x20\x65\x6c\x73\x65\x20\x69\x2a\x66\x28\x69\x2d\x31\x29\x0a\x0a\x69\x3d\x69\x6e\x74\x28\x73\x79\x73\x2e\x61\x72\x67\x76\x5b\x31\x5d\x29\x0a\x70\x72\x69\x6e\x74\x28\x66\x28\x69\x29\x29\x0a')
ลองออนไลน์!
แทนที่ตัวดำเนินการด้วยวิธี dunder
ตัวดำเนินการ python ส่วนใหญ่เป็นน้ำตาลที่เป็นประโยคสำหรับการเรียกเมธอดเฉพาะ (มักเรียกว่า "magic method" หรือ "dunder method" โดย "dunder" จะย่อมาจาก "double underscore") ยกตัวอย่างเช่น+
การโทร__add__()
, ==
สาย__eq__()
และ<<
โทรออก__lshift__()
หากตัวดำเนินการถูก จำกัด คุณสามารถเรียกใช้เมธอดเหล่านี้ได้โดยตรง:
a = 1
print(a.__add__(1).__eq__(2)) # True
ลองออนไลน์!
สำหรับการกำหนดคุณสามารถใช้__setitem__
บนlocals()
หรือglobals()
พจนานุกรมหรือไม่ว่าตัวแปรที่มีอยู่แล้ว:
a = 1
locals().__setitem__('a',2)
locals().__setitem__('b',2)
print(a.__add__(b).__eq__(4)) # True
ลองออนไลน์!
โปรดทราบว่าคุณจะต้องเพิ่มวงเล็บรอบ ๆ ตัวเลขเพื่อหลีกเลี่ยงข้อผิดพลาดทางไวยากรณ์ 4.__eq__(4)
จะไม่ทำงาน แต่(4).__eq__(4)
จะ
วิธีสร้างอักขระด้วยตัวเลขเครื่องหมายคำพูดและเครื่องหมายแบ็กสแลช
สตริงสามารถประกอบด้วยโดย\ooo
ที่ooo
ค่าฐานแปดของอักขระ
เช่น:
'\141'=='a'
นอกจากนี้คุณยังสามารถใช้ hex, ค่าใช้จ่ายของนั้นx
(และa
, b
, c
, d
, e
และ / หรือf
หากพวกเขากำลังใช้):
'\x61'=='a'
และ Unicode โดยเสียค่าใช้จ่ายของu
(สองตัวก่อน Python 3) และอักขระฐานสิบหกหากใช้:
'\u2713'=='✓'
ใช้__import__("module")
แทนimport module
เพื่อหลีกเลี่ยงช่องว่างในimport statement
หรือสร้างชื่อโมดูลแบบไดนามิกเพื่ออิมพอร์ตเป็นสตริง (เช่น"RANDOM".lower()
ถ้าคุณไม่สามารถใช้ตัวพิมพ์เล็กได้d
) ไม่น่าจะมีประโยชน์เพราะคุณไม่ได้มักจะต้องห้องสมุดมาตรฐานและคุณยังจะต้องมีความสามารถในการใช้งาน_
, i
, m
, p
, o
, r
, t
, และ(
)
แก้ไข: หรือตามที่ Ad Hoc Garf Hunter แนะนำคุณสามารถใช้import<tab>module
(ด้วยอักขระแท็บตามตัวอักษร)!
สิ่งนี้อาจไม่เกี่ยวข้องกับคำถาม แต่มันโง่มาก
นี่เป็นวิธีที่พกพาได้ง่ายกว่าของวิธีการที่ซับซ้อนของ water_ghost ในการเข้าถึงวิธีการในตัว
ดัชนีคือ 26 เฉพาะใน CPython 3 การปรับเปลี่ยนที่เล็กมากและเข้าใจง่ายมากช่วยให้ทำงานบน CPython 2.7, CPython 3, PyPy 2.7 และ PyPy 3 (ทดสอบบน Debian 10 amd64)
a = [1, 2, 3]
list(a.__class__.__dict__.values())[[14,13,26,25][sum(map(ord,{__import__("sys").version[0],__import__("platform").python_implementation()[0]}))&3]](a, 4)
print(a)
ดัชนีที่ถูกต้อง (ในระบบของฉัน) คือ
CPython 2.7 13
CPython 3 26
PyPy 2.7 26
PyPy 3 25
และโดยบังเอิญโชคดี('C'+'2')%4 == 1
, ('C'+'3')%4 == 2
, และ('P'+'2') == 2
('P'+'3') == 3
ค่า 14 มีไว้เพื่อหลอกให้คุณคิดว่ามีรูปแบบ
__debug__
เป็นความจริง
ระเบิดตัวเองสวย ... ระเบิด ...
>>> __debug__
True