Apakah mungkin untuk mendefinisikan lebih dari satu fungsi per file di MATLAB, dan mengaksesnya dari luar file itu?

217

Ketika saya sedang belajar untuk gelar sarjana saya di EE, MATLAB mengharuskan setiap fungsi untuk didefinisikan dalam file sendiri, bahkan jika itu adalah satu-liner.

Saya belajar untuk mendapatkan gelar sarjana sekarang, dan saya harus menulis proyek di MATLAB. Apakah ini masih merupakan persyaratan untuk versi MATLAB yang lebih baru?

Jika dimungkinkan untuk menempatkan lebih dari satu fungsi dalam file, apakah ada batasan untuk ini? Misalnya, apakah semua fungsi dalam file dapat diakses dari luar file, atau hanya fungsi yang memiliki nama yang sama dengan file?

Catatan: Saya menggunakan rilis MATLAB R2007b.

Nathan Fellman
sumber

Jawaban:

271

Fungsi pertama dalam file-m (yaitu fungsi utama ), dipanggil ketika file-m dipanggil. Tidak perlu bahwa fungsi utama memiliki nama yang sama dengan file-m, tetapi untuk kejelasan seharusnya . Ketika fungsi dan nama file berbeda, nama file harus digunakan untuk memanggil fungsi utama.

Semua fungsi selanjutnya dalam file-m, yang disebut fungsi lokal (atau "subfungsi" dalam terminologi yang lebih lama), hanya dapat dipanggil oleh fungsi utama dan fungsi lokal lainnya dalam file-m itu. Fungsi di m-file lain tidak dapat memanggil mereka. Mulai di R2016b, Anda dapat menambahkan fungsi lokal ke skrip juga, meskipun perilaku pelingkupan masih sama (yaitu mereka hanya dapat dipanggil dari dalam skrip).

Selain itu, Anda juga dapat mendeklarasikan fungsi dalam fungsi lainnya. Ini disebut fungsi bersarang , dan ini hanya bisa dipanggil dari dalam fungsi yang disarangkan. Mereka juga dapat memiliki akses ke variabel dalam fungsi di mana mereka bersarang, yang membuatnya cukup berguna meskipun sedikit sulit untuk dikerjakan.

Lebih banyak makanan untuk dipikirkan ...

Ada beberapa cara di sekitar perilaku pelingkupan fungsi normal yang diuraikan di atas, seperti fungsi lewat berfungsi sebagai argumen keluaran seperti yang disebutkan dalam jawaban dari SCFrench dan Jonas (yang, dimulai pada R2013b, difasilitasi oleh localfunctionsfungsi). Namun, saya tidak akan menyarankan untuk membiasakan diri menggunakan trik seperti itu, karena ada banyak pilihan yang lebih baik untuk mengatur fungsi dan file Anda.

Sebagai contoh, katakanlah Anda memiliki fungsi utama Adalam sebuah m-file A.m, bersama dengan fungsi lokal D, Edan F. Sekarang katakanlah Anda memiliki dua fungsi terkait lainnya Bdan Cdalam m-file B.mdan C.mmasing-masing, bahwa Anda juga ingin dapat menelepon D, Edan F. Berikut beberapa opsi yang Anda miliki:

  • Masukkan D,, Edan Fmasing - masing dalam file-m terpisah masing-masing, yang memungkinkan fungsi lain untuk memanggil mereka. The downside adalah bahwa ruang lingkup fungsi ini adalah besar dan tidak terbatas hanya A, Bdan C, tapi terbalik adalah bahwa ini adalah cukup sederhana.

  • Buat defineMyFunctionsm-file (seperti dalam contoh Jonas') dengan D, E, dan Fsebagai fungsi lokal dan fungsi utama yang hanya kembali berfungsi menangani mereka. Ini memungkinkan Anda untuk menyimpan D,, Edan Fdalam file yang sama, tetapi tidak melakukan apa-apa mengenai ruang lingkup fungsi-fungsi ini karena fungsi apa pun yang dapat memanggil defineMyFunctionsdapat memanggil mereka. Anda juga harus khawatir tentang melewati fungsi menangani sebagai argumen untuk memastikan Anda memilikinya di mana Anda membutuhkannya.

  • Salin D, Edan Fke dalam B.mdan C.msebagai fungsi lokal. Ini membatasi ruang lingkup penggunaannya hanya A,, Bdan C, tetapi membuat pembaruan dan pemeliharaan kode Anda menjadi mimpi buruk karena Anda memiliki tiga salinan kode yang sama di tempat yang berbeda.

  • Gunakan fungsi pribadi ! Jika Anda memiliki A, B, dan Cdalam direktori yang sama, Anda dapat membuat subdirektori bernama privatedan tempat D, Edan Fdi sana, masing-masing sebagai m-file terpisah. Hal ini membatasi ruang lingkup mereka sehingga mereka hanya dapat dipanggil oleh fungsi dalam direktori segera di atas (yaitu A, B, dan C) dan membuat mereka bersama-sama di tempat yang sama (tapi masih berbeda m-file):

    myDirectory/
        A.m
        B.m
        C.m
        private/
            D.m
            E.m
            F.m

Semua ini agak di luar ruang lingkup pertanyaan Anda, dan mungkin lebih detail daripada yang Anda butuhkan, tapi saya pikir mungkin lebih baik untuk menyentuh pada keprihatinan yang lebih umum dari mengatur semua file-m Anda. ;)

gnovice
sumber
3
Pilihan jawaban favorit terlihat seperti ini ^, @idigas
embert
1
@embert Saya berasumsi maksudnya di sepanjang garis pertanyaan favorit, yang dapat dipilih secara independen dari favorit.
OJFord
79

Secara umum, jawaban untuk pertanyaan Anda adalah tidak, Anda tidak dapat menetapkan lebih dari satu fungsi yang terlihat secara eksternal per file. Anda dapat mengembalikan gagang fungsi ke fungsi lokal, dan cara mudah untuk melakukannya adalah dengan membuatnya menjadi bidang struct. Berikut ini sebuah contoh:

function funs = makefuns
  funs.fun1=@fun1;
  funs.fun2=@fun2;
end

function y=fun1(x)
  y=x;
end

function z=fun2
  z=1;
end

Dan inilah cara penggunaannya:

>> myfuns = makefuns;
>> myfuns.fun1(5)    
ans =
     5
>> myfuns.fun2()     
ans =
     1
SCFrench
sumber
36

Satu-satunya cara untuk memiliki beberapa fungsi yang dapat diakses secara terpisah dalam satu file adalah dengan mendefinisikan METODE STATIK menggunakan pemrograman berorientasi objek . Anda akan mengakses fungsinya sebagai myClass.static1(), myClass.static2()dll.

Fungsionalitas OOP hanya didukung secara resmi sejak R2008a, jadi kecuali Anda ingin menggunakan sintaks OOP yang lama dan tidak berdokumen, jawabannya tidak, seperti dijelaskan oleh @gnovice .

EDIT

Satu lagi cara untuk mendefinisikan beberapa fungsi di dalam file yang dapat diakses dari luar adalah dengan membuat fungsi yang mengembalikan banyak fungsi . Dengan kata lain, Anda akan memanggil fungsi pendefinisian Anda sebagai [fun1,fun2,fun3]=defineMyFunctions, setelah itu Anda dapat menggunakan out1=fun1(inputs)dll.

Jonas
sumber
Saya tidak akan menggunakan oop untuk tujuan ini, ia menambahkan overhead substansial terutama untuk metode statis. ( stackoverflow.com/questions/1693429/… )
Daniel
1
@Aniel: overhead hanya terlihat jika Anda melakukan sejumlah besar panggilan fungsi dan perhitungan dalam metode ini semi-instan. Kedua kondisi tersebut sering menunjukkan desain yang buruk - tidak ada vektorisasi, dan fungsi yang tidak berarti. Jadi, saya tidak akan terlalu khawatir.
Jonas
23

Saya sangat suka jawaban SCFrench - Saya ingin menunjukkan bahwa itu dapat dengan mudah dimodifikasi untuk mengimpor fungsi langsung ke ruang kerja menggunakan fungsi assignin. (Melakukannya seperti ini mengingatkan saya banyak cara "impor x dari y" Python untuk melakukan sesuatu)

function message = makefuns
  assignin('base','fun1',@fun1);
  assignin('base','fun2',@fun2);
  message='Done importing functions to workspace';
end

function y=fun1(x)
  y=x;
end

function z=fun2
  z=1;
end

Dan kemudian digunakan sebagai berikut:

>> makefuns
ans =
Done importing functions to workspace

>> fun1(123)
ans =
   123

>> fun2()
ans =
     1
Ru Hasha
sumber
assignin('caller',...)akan lebih benar. Anda mungkin ingin menggunakan fungsi-fungsi ini dari dalam fungsi lain.
Cris Luengo
10

Sejalan dengan jawaban SCFrench, tetapi dengan putaran gaya C # yang lebih banyak ..

Saya akan (dan sering melakukannya) membuat kelas yang berisi beberapa metode statis. Sebagai contoh:

classdef Statistics

    methods(Static)
        function val = MyMean(data)
            val = mean(data);
        end

        function val = MyStd(data)
            val = std(data);
        end
    end

end

Karena metodenya statis, Anda tidak perlu mengatur kelas. Anda memanggil fungsi sebagai berikut:

data = 1:10;

mean = Statistics.MyMean(data);
std = Statistics.MyStd(data);     
SmallJoeMan
sumber
4

Saya mendefinisikan beberapa fungsi dalam satu file .m dengan Oktaf dan kemudian menggunakan perintah dari dalam file .m di mana saya perlu menggunakan fungsi dari file itu:

source("mycode.m");

Tidak yakin apakah ini tersedia dengan Matlab.

octave:8> help source
'source' is a built-in function

 -- Built-in Function:  source (FILE)
     Parse and execute the contents of FILE.  This is equivalent to
     executing commands from a script file, but without requiring the
     file to be named `FILE.m'.
JD
sumber
3

Anda juga dapat mengelompokkan fungsi dalam satu file utama bersama dengan fungsi utama yang tampak seperti ini:

function [varargout] = main( subfun, varargin )
[varargout{1:nargout}] = feval( subfun, varargin{:} ); 

% paste your subfunctions below ....
function str=subfun1
str='hello'

Kemudian memanggil subfun1 akan terlihat seperti ini: str = main ('subfun1')

Thierry Dalon
sumber
0

Pada R2017b, ini tidak mungkin secara resmi. The dokumentasi yang relevan menyatakan bahwa:

File program dapat berisi banyak fungsi. Jika file hanya berisi definisi fungsi, fungsi pertama adalah fungsi utama, dan merupakan fungsi yang MATLAB kaitkan dengan nama file. Fungsi yang mengikuti fungsi utama atau kode skrip disebut fungsi lokal. Fungsi lokal hanya tersedia dalam file.

Namun, solusi yang disarankan dalam jawaban lain dapat mencapai hal serupa.

Setan
sumber
Ini bukan apa yang dikatakan Gnovice di awal jawabannya?
Adiel
@Adiel Mungkin, tetapi beberapa tahun telah berlalu sejak jawaban itu, dan seseorang mungkin bertanya-tanya apakah ada yang berubah.
Dev-iL
Saya masih belum mengerti jika ada yang berubah ...? :)
Adiel
Nggak. Selain mungkin beberapa dokumentasi yang ditambahkan untuk membahas topik khusus ini.
Dev-iL
Alasan mengapa saya menulis jawaban ini adalah karena beberapa rilis yang lalu mereka memperkenalkan fungsi yang dapat Anda tambahkan ke akhir skrip - jadi orang mungkin bertanya-tanya apakah ada yang berubah dalam hal ini juga (jawaban: tidak).
Dev-iL
-1

Saya telah mencoba dengan SCFRench dan dengan Ru Hasha pada oktaf.

Dan akhirnya berhasil: tetapi saya telah melakukan beberapa modifikasi

function message = makefuns
    assignin('base','fun1', @fun1);   % Ru Hasha
    assignin('base', 'fun2', @fun2);  % Ru Hasha
    message.fun1=@fun1;               % SCFrench
    message.fun2=@fun2;               % SCFrench
end

function y=fun1(x)
    y=x;
end

function z=fun2
    z=1;
end

Dapat dipanggil dalam file 'm' lain:

printf("%d\n", makefuns.fun1(123));
printf("%d\n", makefuns.fun2());

memperbarui:

Saya menambahkan jawaban karena tidak yang 72 maupun 20 bekerja di oktaf untuk saya. Yang saya tulis bekerja dengan sempurna (dan saya mengujinya Jumat lalu ketika saya kemudian menulis posting).

Gromph
sumber
2
Jika Anda dapat menjelaskan bagaimana ini berbeda dari dua jawaban yang ada yang Anda salin, saya akan menghapus downvote saya. Maaf karena tidak berkomentar sebelumnya. Saya hanya tidak melihat bagaimana ini berbeda, kecuali Anda menggabungkan kedua metode menjadi satu fungsi dan karena itu melakukan sesuatu yang berlebihan. Juga, silakan masukkan tautan yang tepat ke jawaban yang Anda rujuk, "+72" dan "+20" cukup samar, butuh beberapa saat untuk menyadari bahwa Anda merujuk pada penghitungan suara, yang akan berubah seiring waktu dan menjadikan referensi Anda tidak dapat dimengerti.
Cris Luengo