หากเป้าหมายคือการให้เอฟเฟกต์แบบเดียวกันกับโค้ดของคุณที่ #ifdef WINDOWS / #endif มี .. นี่เป็นวิธีที่จะทำ (ฉันใช้ mac btw)
กรณีง่ายไม่มีการผูกมัด
>>> def _ifdef_decorator_impl(plat, func, frame):
... if platform.system() == plat:
... return func
... elif func.__name__ in frame.f_locals:
... return frame.f_locals[func.__name__]
... else:
... def _not_implemented(*args, **kwargs):
... raise NotImplementedError(
... f"Function {func.__name__} is not defined "
... f"for platform {platform.system()}.")
... return _not_implemented
...
...
>>> def windows(func):
... return _ifdef_decorator_impl('Windows', func, sys._getframe().f_back)
...
>>> def macos(func):
... return _ifdef_decorator_impl('Darwin', func, sys._getframe().f_back)
ด้วยการใช้งานนี้คุณจะได้รับไวยากรณ์เดียวกับที่คุณมีในคำถามของคุณ
>>> @macos
... def zulu():
... print("world")
...
>>> @windows
... def zulu():
... print("hello")
...
>>> zulu()
world
>>>
สิ่งที่โค้ดข้างต้นกำลังทำคือการกำหนดซูลูให้กับซูลูหากแพลตฟอร์มตรงกัน หากแพลตฟอร์มไม่ตรงกันจะส่งคืนซูลูหากมีการกำหนดไว้ก่อนหน้านี้ หากไม่ได้กำหนดไว้จะส่งคืนฟังก์ชันตัวยึดตำแหน่งที่ยกข้อยกเว้น
นักตกแต่งเป็นแนวคิดที่ง่ายต่อการเข้าใจหากคุณจำได้ว่า
@mydecorator
def foo():
pass
คล้ายกับ:
foo = mydecorator(foo)
นี่คือการใช้งานโดยใช้เครื่องมือตกแต่งพารามิเตอร์:
>>> def ifdef(plat):
... frame = sys._getframe().f_back
... def _ifdef(func):
... return _ifdef_decorator_impl(plat, func, frame)
... return _ifdef
...
>>> @ifdef('Darwin')
... def ice9():
... print("nonsense")
foo = mydecorator(param)(foo)
ตกแต่งแปรเป็นคล้ายกับ
ฉันได้อัพเดตคำตอบแล้ว เพื่อตอบสนองต่อความคิดเห็นฉันได้ขยายขอบเขตดั้งเดิมเพื่อรวมแอปพลิเคชันไปยังวิธีการเรียนและครอบคลุมฟังก์ชั่นที่กำหนดในโมดูลอื่น ๆ ในการอัพเดทครั้งล่าสุดนี้ฉันสามารถลดความซับซ้อนที่เกี่ยวข้องในการพิจารณาว่าฟังก์ชั่นได้รับการกำหนดแล้ว
[อัพเดทเล็ก ๆ น้อย ๆ ที่นี่ ... ฉันไม่สามารถวางมันลงได้ - มันเป็นแบบฝึกหัดที่สนุก] ฉันทำการทดสอบเพิ่มเติมแล้วและพบว่ามันใช้งานได้โดยทั่วไปใน callables - ไม่ใช่แค่ฟังก์ชั่นธรรมดา คุณสามารถตกแต่งการประกาศคลาสว่า callable หรือไม่ และรองรับฟังก์ชั่นด้านในของฟังก์ชั่นดังนั้นสิ่งนี้เป็นไปได้ (แม้ว่าอาจจะไม่ใช่สไตล์ที่ดี - นี่เป็นเพียงรหัสทดสอบ):
>>> @macos
... class CallableClass:
...
... @macos
... def __call__(self):
... print("CallableClass.__call__() invoked.")
...
... @macos
... def func_with_inner(self):
... print("Defining inner function.")
...
... @macos
... def inner():
... print("Inner function defined for Darwin called.")
...
... @windows
... def inner():
... print("Inner function for Windows called.")
...
... inner()
...
... @macos
... class InnerClass:
...
... @macos
... def inner_class_function(self):
... print("Called inner_class_function() Mac.")
...
... @windows
... def inner_class_function(self):
... print("Called inner_class_function() for windows.")
ข้างต้นแสดงให้เห็นถึงกลไกพื้นฐานของการตกแต่งวิธีการเข้าถึงขอบเขตของผู้โทรและวิธีการลดความซับซ้อนของมัณฑนากรหลายคนที่มีพฤติกรรมที่คล้ายกันโดยมีฟังก์ชั่นภายในที่มีขั้นตอนวิธีการทั่วไปที่กำหนดไว้
สายสนับสนุน
เพื่อสนับสนุนการโยงนักตกแต่งเหล่านี้ซึ่งระบุว่าฟังก์ชั่นใช้กับแพลตฟอร์มมากกว่าหนึ่งอันมัณฑนากรสามารถนำไปใช้ได้ดังนี้:
>>> class IfDefDecoratorPlaceholder:
... def __init__(self, func):
... self.__name__ = func.__name__
... self._func = func
...
... def __call__(self, *args, **kwargs):
... raise NotImplementedError(
... f"Function {self._func.__name__} is not defined for "
... f"platform {platform.system()}.")
...
>>> def _ifdef_decorator_impl(plat, func, frame):
... if platform.system() == plat:
... if type(func) == IfDefDecoratorPlaceholder:
... func = func._func
... frame.f_locals[func.__name__] = func
... return func
... elif func.__name__ in frame.f_locals:
... return frame.f_locals[func.__name__]
... elif type(func) == IfDefDecoratorPlaceholder:
... return func
... else:
... return IfDefDecoratorPlaceholder(func)
...
>>> def linux(func):
... return _ifdef_decorator_impl('Linux', func, sys._getframe().f_back)
วิธีที่คุณสนับสนุนการโยง:
>>> @macos
... @linux
... def foo():
... print("works!")
...
>>> foo()
works!
my_callback = windows(<actual function definition>)
- ดังนั้นชื่อmy_callback
จะถูกเขียนทับโดยไม่คำนึงถึงสิ่งที่มัณฑนากรอาจทำ วิธีเดียวที่ฟังก์ชั่นรุ่นลีนุกซ์อาจสิ้นสุดลงในตัวแปรนั้นคือถ้าwindows()
ส่งคืน - แต่ฟังก์ชั่นนั้นไม่มีทางรู้เกี่ยวกับรุ่นลีนุกซ์ ฉันคิดว่าวิธีทั่วไปในการบรรลุเป้าหมายนี้คือการมีคำจำกัดความของฟังก์ชั่นเฉพาะระบบปฏิบัติการในไฟล์แยกกันและมีimport
เพียงหนึ่งเงื่อนไขเท่านั้น